// import 'package:flutter/cupertino.dart';
// import 'package:flutter/gestures.dart';
// import 'package:flutter/rendering.dart';
// import 'dart:math' as math;

// class MySingleChildScrollView extends StatelessWidget {
//   /// Creates a box in which a single widget can be scrolled.
//   const MySingleChildScrollView({
//     super.key,
//     this.scrollDirection = Axis.vertical,
//     this.reverse = false,
//     this.padding,
//     this.primary,
//     this.physics,
//     this.controller,
//     this.child,
//     this.dragStartBehavior = DragStartBehavior.start,
//     this.clipBehavior = Clip.hardEdge,
//     this.restorationId,
//     this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
//   }) : assert(
//           !(controller != null && (primary ?? false)),
//           'Primary ScrollViews obtain their ScrollController via inheritance '
//           'from a PrimaryScrollController widget. You cannot both set primary to '
//           'true and pass an explicit controller.',
//         );

//   /// {@macro flutter.widgets.scroll_view.scrollDirection}
//   final Axis scrollDirection;

//   /// Whether the scroll view scrolls in the reading direction.
//   ///
//   /// For example, if the reading direction is left-to-right and
//   /// [scrollDirection] is [Axis.horizontal], then the scroll view scrolls from
//   /// left to right when [reverse] is false and from right to left when
//   /// [reverse] is true.
//   ///
//   /// Similarly, if [scrollDirection] is [Axis.vertical], then the scroll view
//   /// scrolls from top to bottom when [reverse] is false and from bottom to top
//   /// when [reverse] is true.
//   ///
//   /// Defaults to false.
//   final bool reverse;

//   /// The amount of space by which to inset the child.
//   final EdgeInsetsGeometry? padding;

//   /// An object that can be used to control the position to which this scroll
//   /// view is scrolled.
//   ///
//   /// Must be null if [primary] is true.
//   ///
//   /// A [ScrollController] serves several purposes. It can be used to control
//   /// the initial scroll position (see [ScrollController.initialScrollOffset]).
//   /// It can be used to control whether the scroll view should automatically
//   /// save and restore its scroll position in the [PageStorage] (see
//   /// [ScrollController.keepScrollOffset]). It can be used to read the current
//   /// scroll position (see [ScrollController.offset]), or change it (see
//   /// [ScrollController.animateTo]).
//   final ScrollController? controller;

//   /// {@macro flutter.widgets.scroll_view.primary}
//   final bool? primary;

//   /// How the scroll view should respond to user input.
//   ///
//   /// For example, determines how the scroll view continues to animate after the
//   /// user stops dragging the scroll view.
//   ///
//   /// Defaults to matching platform conventions.
//   final ScrollPhysics? physics;

//   /// The widget that scrolls.
//   ///
//   /// {@macro flutter.widgets.ProxyWidget.child}
//   final Widget? child;

//   /// {@macro flutter.widgets.scrollable.dragStartBehavior}
//   final DragStartBehavior dragStartBehavior;

//   /// {@macro flutter.material.Material.clipBehavior}
//   ///
//   /// Defaults to [Clip.hardEdge].
//   final Clip clipBehavior;

//   /// {@macro flutter.widgets.scrollable.restorationId}
//   final String? restorationId;

//   /// {@macro flutter.widgets.scroll_view.keyboardDismissBehavior}
//   final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;

//   AxisDirection _getDirection(BuildContext context) {
//     return getAxisDirectionFromAxisReverseAndDirectionality(
//         context, scrollDirection, reverse);
//   }

//   @override
//   Widget build(BuildContext context) {
//     final AxisDirection axisDirection = _getDirection(context);
//     Widget? contents = child;
//     if (padding != null) {
//       contents = Padding(padding: padding!, child: contents);
//     }
//     final bool effectivePrimary = primary ??
//         controller == null &&
//             PrimaryScrollController.shouldInherit(context, scrollDirection);

//     final ScrollController? scrollController = effectivePrimary
//         ? PrimaryScrollController.maybeOf(context)
//         : controller;

//     Widget scrollable = Scrollable(
//       dragStartBehavior: dragStartBehavior,
//       axisDirection: axisDirection,
//       controller: scrollController,
//       physics: physics,
//       restorationId: restorationId,
//       viewportBuilder: (BuildContext context, ViewportOffset offset) {
//         return _SingleChildViewport(
//           axisDirection: axisDirection,
//           offset: offset,
//           clipBehavior: clipBehavior,
//           child: contents,
//         );
//       },
//     );

//     if (keyboardDismissBehavior == ScrollViewKeyboardDismissBehavior.onDrag) {
//       scrollable = NotificationListener<ScrollUpdateNotification>(
//         child: scrollable,
//         onNotification: (ScrollUpdateNotification notification) {
//           final FocusScopeNode focusNode = FocusScope.of(context);
//           if (notification.dragDetails != null && focusNode.hasFocus) {
//             focusNode.unfocus();
//           }
//           return false;
//         },
//       );
//     }

//     return effectivePrimary && scrollController != null
//         // Further descendant ScrollViews will not inherit the same
//         // PrimaryScrollController
//         ? PrimaryScrollController.none(child: scrollable)
//         : scrollable;
//   }
// }

// class _SingleChildViewport extends SingleChildRenderObjectWidget {
//   const _SingleChildViewport({
//     this.axisDirection = AxisDirection.down,
//     required this.offset,
//     super.child,
//     required this.clipBehavior,
//   });

//   final AxisDirection axisDirection;
//   final ViewportOffset offset;
//   final Clip clipBehavior;

//   @override
//   _RenderSingleChildViewport createRenderObject(BuildContext context) {
//     return _RenderSingleChildViewport(
//       axisDirection: axisDirection,
//       offset: offset,
//       clipBehavior: clipBehavior,
//     );
//   }

//   @override
//   SingleChildRenderObjectElement createElement() {
//     return _SingleChildViewportElement(this);
//   }
// }

// class _SingleChildViewportElement extends SingleChildRenderObjectElement
//     with NotifiableElementMixin, ViewportElementMixin {
//   _SingleChildViewportElement(_SingleChildViewport super.widget);
// }

// class _RenderSingleChildViewport extends RenderBox
//     with RenderObjectWithChildMixin<RenderBox>
//     implements RenderAbstractViewport {
//   _RenderSingleChildViewport({
//     AxisDirection axisDirection = AxisDirection.down,
//     required ViewportOffset offset,
//     RenderBox? child,
//     required Clip clipBehavior,
//   })  : _axisDirection = axisDirection,
//         _offset = offset,
//         _clipBehavior = clipBehavior {
//     this.child = child;
//   }

//   AxisDirection get axisDirection => _axisDirection;
//   AxisDirection _axisDirection;
//   set axisDirection(AxisDirection value) {
//     if (value == _axisDirection) {
//       return;
//     }
//     _axisDirection = value;
//     markNeedsLayout();
//   }

//   Axis get axis => axisDirectionToAxis(axisDirection);

//   ViewportOffset get offset => _offset;
//   ViewportOffset _offset;
//   set offset(ViewportOffset value) {
//     if (value == _offset) {
//       return;
//     }
//     if (attached) {
//       _offset.removeListener(_hasScrolled);
//     }
//     _offset = value;
//     if (attached) {
//       _offset.addListener(_hasScrolled);
//     }
//     markNeedsLayout();
//   }

//   /// {@macro flutter.material.Material.clipBehavior}
//   ///
//   /// Defaults to [Clip.none], and must not be null.
//   Clip get clipBehavior => _clipBehavior;
//   Clip _clipBehavior = Clip.none;
//   set clipBehavior(Clip value) {
//     if (value != _clipBehavior) {
//       _clipBehavior = value;
//       markNeedsPaint();
//       markNeedsSemanticsUpdate();
//     }
//   }

//   void _hasScrolled() {
//     markNeedsPaint();
//     markNeedsSemanticsUpdate();
//   }

//   @override
//   void setupParentData(RenderObject child) {
//     // We don't actually use the offset argument in BoxParentData, so let's
//     // avoid allocating it at all.
//     if (child.parentData is! ParentData) {
//       child.parentData = ParentData();
//     }
//   }

//   @override
//   void attach(PipelineOwner owner) {
//     super.attach(owner);
//     _offset.addListener(_hasScrolled);
//   }

//   @override
//   void detach() {
//     _offset.removeListener(_hasScrolled);
//     super.detach();
//   }

//   @override
//   bool get isRepaintBoundary => true;

//   double get _viewportExtent {
//     assert(hasSize);
//     switch (axis) {
//       case Axis.horizontal:
//         return size.width;
//       case Axis.vertical:
//         return size.height;
//     }
//   }

//   double get _minScrollExtent {
//     assert(hasSize);
//     return 0.0;
//   }

//   double get _maxScrollExtent {
//     assert(hasSize);
//     if (child == null) {
//       return 0.0;
//     }
//     switch (axis) {
//       case Axis.horizontal:
//         return math.max(0.0, child!.size.width - size.width);
//       case Axis.vertical:
//         return math.max(0.0, child!.size.height - size.height);
//     }
//   }

//   BoxConstraints _getInnerConstraints(BoxConstraints constraints) {
//     switch (axis) {
//       case Axis.horizontal:
//         return constraints.heightConstraints();
//       case Axis.vertical:
//         return constraints.widthConstraints();
//     }
//   }

//   @override
//   double computeMinIntrinsicWidth(double height) {
//     if (child != null) {
//       return child!.getMinIntrinsicWidth(height);
//     }
//     return 0.0;
//   }

//   @override
//   double computeMaxIntrinsicWidth(double height) {
//     if (child != null) {
//       return child!.getMaxIntrinsicWidth(height);
//     }
//     return 0.0;
//   }

//   @override
//   double computeMinIntrinsicHeight(double width) {
//     if (child != null) {
//       return child!.getMinIntrinsicHeight(width);
//     }
//     return 0.0;
//   }

//   @override
//   double computeMaxIntrinsicHeight(double width) {
//     if (child != null) {
//       return child!.getMaxIntrinsicHeight(width);
//     }
//     return 0.0;
//   }

//   // We don't override computeDistanceToActualBaseline(), because we
//   // want the default behavior (returning null). Otherwise, as you
//   // scroll, it would shift in its parent if the parent was baseline-aligned,
//   // which makes no sense.

//   @override
//   Size computeDryLayout(BoxConstraints constraints) {
//     if (child == null) {
//       return constraints.smallest;
//     }
//     final Size childSize =
//         child!.getDryLayout(_getInnerConstraints(constraints));
//     return constraints.constrain(childSize);
//   }

//   @override
//   void performLayout() {
//     final BoxConstraints constraints = this.constraints;
//     if (child == null) {
//       size = constraints.smallest;
//     } else {
//       child!.layout(_getInnerConstraints(constraints), parentUsesSize: true);
//       size = constraints.constrain(child!.size);
//     }

//     offset.applyViewportDimension(_viewportExtent);
//     offset.applyContentDimensions(_minScrollExtent, _maxScrollExtent);
//   }

//   Offset get _paintOffset => _paintOffsetForPosition(offset.pixels);

//   Offset _paintOffsetForPosition(double position) {
//     switch (axisDirection) {
//       case AxisDirection.up:
//         return Offset(0.0, position - child!.size.height + size.height);
//       case AxisDirection.down:
//         return Offset(0.0, -position);
//       case AxisDirection.left:
//         return Offset(position - child!.size.width + size.width, 0.0);
//       case AxisDirection.right:
//         return Offset(-position, 0.0);
//     }
//   }

//   bool _shouldClipAtPaintOffset(Offset paintOffset) {
//     assert(child != null);
//     switch (clipBehavior) {
//       case Clip.none:
//         return false;
//       case Clip.hardEdge:
//       case Clip.antiAlias:
//       case Clip.antiAliasWithSaveLayer:
//         return paintOffset.dx < 0 ||
//             paintOffset.dy < 0 ||
//             paintOffset.dx + child!.size.width > size.width ||
//             paintOffset.dy + child!.size.height > size.height;
//     }
//   }

//   @override
//   void paint(PaintingContext context, Offset offset) {
//     if (child != null) {
//       final Offset paintOffset = _paintOffset;

//       void paintContents(PaintingContext context, Offset offset) {
//         context.paintChild(child!, offset + paintOffset);
//       }

//       if (_shouldClipAtPaintOffset(paintOffset)) {
//         _clipRectLayer.layer = context.pushClipRect(
//           needsCompositing,
//           offset,
//           Offset.zero & size,
//           paintContents,
//           clipBehavior: clipBehavior,
//           oldLayer: _clipRectLayer.layer,
//         );
//       } else {
//         _clipRectLayer.layer = null;
//         paintContents(context, offset);
//       }
//     }
//   }

//   final LayerHandle<ClipRectLayer> _clipRectLayer =
//       LayerHandle<ClipRectLayer>();

//   @override
//   void dispose() {
//     _clipRectLayer.layer = null;
//     super.dispose();
//   }

//   @override
//   void applyPaintTransform(RenderBox child, Matrix4 transform) {
//     final Offset paintOffset = _paintOffset;
//     transform.translate(paintOffset.dx, paintOffset.dy);
//   }

//   @override
//   Rect? describeApproximatePaintClip(RenderObject? child) {
//     if (child != null && _shouldClipAtPaintOffset(_paintOffset)) {
//       return Offset.zero & size;
//     }
//     return null;
//   }

//   @override
//   bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
//     if (child != null) {
//       return result.addWithPaintOffset(
//         offset: _paintOffset,
//         position: position,
//         hitTest: (BoxHitTestResult result, Offset transformed) {
//           assert(transformed == position + -_paintOffset);
//           return child!.hitTest(result, position: transformed);
//         },
//       );
//     }
//     return false;
//   }

//   @override
//   RevealedOffset getOffsetToReveal(RenderObject target, double alignment,
//       {Rect? rect}) {
//     rect ??= target.paintBounds;
//     if (target is! RenderBox) {
//       return RevealedOffset(offset: offset.pixels, rect: rect);
//     }

//     final RenderBox targetBox = target;
//     final Matrix4 transform = targetBox.getTransformTo(child);
//     final Rect bounds = MatrixUtils.transformRect(transform, rect);
//     final Size contentSize = child!.size;

//     final double leadingScrollOffset;
//     final double targetMainAxisExtent;
//     final double mainAxisExtent;

//     switch (axisDirection) {
//       case AxisDirection.up:
//         mainAxisExtent = size.height;
//         leadingScrollOffset = contentSize.height - bounds.bottom;
//         targetMainAxisExtent = bounds.height;
//         break;
//       case AxisDirection.right:
//         mainAxisExtent = size.width;
//         leadingScrollOffset = bounds.left;
//         targetMainAxisExtent = bounds.width;
//         break;
//       case AxisDirection.down:
//         mainAxisExtent = size.height;
//         leadingScrollOffset = bounds.top;
//         targetMainAxisExtent = bounds.height;
//         break;
//       case AxisDirection.left:
//         mainAxisExtent = size.width;
//         leadingScrollOffset = contentSize.width - bounds.right;
//         targetMainAxisExtent = bounds.width;
//     }

//     final double targetOffset = leadingScrollOffset -
//         (mainAxisExtent - targetMainAxisExtent) * alignment;
//     final Rect targetRect = bounds.shift(_paintOffsetForPosition(targetOffset));
//     return RevealedOffset(offset: targetOffset, rect: targetRect);
//   }

//   @override
//   void showOnScreen({
//     RenderObject? descendant,
//     Rect? rect,
//     Duration duration = Duration.zero,
//     Curve curve = Curves.ease,
//   }) {
//     if (!offset.allowImplicitScrolling) {
//       return super.showOnScreen(
//         descendant: descendant,
//         rect: rect,
//         duration: duration,
//         curve: curve,
//       );
//     }

//     final Rect? newRect = RenderViewportBase.showInViewport(
//       descendant: descendant,
//       viewport: this,
//       offset: offset,
//       rect: rect,
//       duration: duration,
//       curve: curve,
//     );
//     super.showOnScreen(
//       rect: newRect,
//       duration: duration,
//       curve: curve,
//     );
//   }

//   @override
//   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
//     super.debugFillProperties(properties);
//     properties.add(DiagnosticsProperty<Offset>('offset', _paintOffset));
//   }

//   @override
//   Rect describeSemanticsClip(RenderObject child) {
//     final double remainingOffset = _maxScrollExtent - offset.pixels;
//     switch (axisDirection) {
//       case AxisDirection.up:
//         return Rect.fromLTRB(
//           semanticBounds.left,
//           semanticBounds.top - remainingOffset,
//           semanticBounds.right,
//           semanticBounds.bottom + offset.pixels,
//         );
//       case AxisDirection.right:
//         return Rect.fromLTRB(
//           semanticBounds.left - offset.pixels,
//           semanticBounds.top,
//           semanticBounds.right + remainingOffset,
//           semanticBounds.bottom,
//         );
//       case AxisDirection.down:
//         return Rect.fromLTRB(
//           semanticBounds.left,
//           semanticBounds.top - offset.pixels,
//           semanticBounds.right,
//           semanticBounds.bottom + remainingOffset,
//         );
//       case AxisDirection.left:
//         return Rect.fromLTRB(
//           semanticBounds.left - remainingOffset,
//           semanticBounds.top,
//           semanticBounds.right + offset.pixels,
//           semanticBounds.bottom,
//         );
//     }
//   }
// }
